在前一章節中,我們探討了 HotSpot JVM 及其核心的 JIT 編譯技術。HotSpot 透過「熱點」檢測和即時編譯,能夠在應用運行過程中不斷優化程式碼,從而在性能和資源使用之間取得平衡。然而,隨著現代應用場景的快速變化,特別是在 微服務 和 雲端原生應用 中,快速啟動和資源效率變得更加重要,這對傳統的 JIT 模式提出了挑戰。
為了解決這些需求,GraalVM 應運而生。作為對 HotSpot 的擴展,GraalVM 不僅延續了 JVM 的核心特性,還引入了更先進的 Ahead-of-Time (AOT) 編譯技術 和強大的多語言支持框架 Truffle,使得它能夠在各種應用場景中提供更快的啟動時間和更靈活的語言整合。
下圖為架構示意, GraalVM基於 HotSpot 的擴展,它在保留 HotSpot 的優勢之外,通過兩個關鍵特性進一步提升性能:
GraalVM Compiler 是一個高效的 動態即時編譯器 (JIT),由 Java 編寫,並與 HotSpot JVM 緊密集成。它通過 JVM Compiler Interface (JVMCI) 與 JVM 進行互動,可以動態將 Java 位元組轉換為高效的機器碼。以下是這三個技術在 GraalVM 編譯器中的具體角色:
Ahead-of-Time 編譯技術 (AOT)
AOT 編譯 是 GraalVM 的核心技術之一,它通過 Native Image 將 Java 及其他基於 JVM 的程式碼在運行之前直接編譯為本地機器碼。這樣編譯過後的應用可以獲得接近原生應用的性能,並且啟動速度極快,適合需要快速啟動和低資源占用的應用場景,如微服務和容器化應用。
GraalVM 編譯器 的 AOT 功能使應用在運行時不再依賴於 JVM 的即時編譯 (JIT),而是直接運行已經編譯好的本地程式碼,這大幅提升了應用的啟動速度和資源效率。
Partial Escape Analysis
Graal 編譯器中的一項動態優化技術,用來消除不必要的物件分配。當 GraalVM 編譯器判斷某個物件只在方法內部使用且不會『逸出』到方法外部時,它可以優化這些物件的分配,避免將它們分配到堆記憶體中,甚至完全消除這些分配。
GraalVM 編譯器 使用這項技術來減少垃圾回收的負擔,優化程式碼運行的記憶體管理,從而提升應用的整體運行效率。
Graph Compilation
將不同程式語言的程式碼轉換為一種通用的中介表示(IR),即一種圖形化的程式碼結構。這讓 GraalVM 能夠對多種語言的程式碼(如 Java、JavaScript、Ruby、Python、R 等)進行統一的優化與編譯。簡單來說就是將程式碼的控制流程與數據流表示為一個圖形結構(通常是控制流程圖或數據流圖)。簡單來說就是利用圖形演算法(如圖的遍歷、縮減、優化路徑等)的技術來進行程式碼的優化與轉換
Graal 編譯器使用這個通用的圖形表示進行語言無關的優化,無論是哪種語言,編譯器都能在這個圖上進行優化與程式碼生成,從而實現高效的跨語言執行。
簡易比較 傳統的 JVM (Origin VM) 和 GraalVM 中的編譯器架構如下圖(圖Source請點我)。GraalVM 中的 Graal 編譯器取代了傳統的 C2 編譯器,提供了先進的優化技術,特別是支持 AOT 和多語言協作,這是傳統 HotSpot JVM 所不具備的功能。另外引入了 JVMCI(JVM Compiler Interface),使得 Graal 編譯器可以更靈活地與 JVM 溝通,這也是 GraalVM 支持動態編譯和多語言運行的重要基礎。
| JVMCI允許 Graal 編譯器這類高階編譯器能夠與 JVM 互動,讀取位元碼、提取中繼資料,並將編譯後的機器碼注入 JVM 中。
流程如下
Step1: 編譯:將應用程式碼經由 javac
編譯為位元碼(.class
檔案)。
Step2: 打包:使用 Buildpack 打包成一個可執行的 .jar
檔案,並將其放入容器中。
容器結構:容器內有三層:
application.jar
):打包好的 Spring Boot 應用。在這種傳統方式下,應用啟動時間通常較長,因為它依賴 JVM 的即時編譯(Just-In-Time, JIT)來執行。
流程如下
Step1: AOT 優化:在程式編譯之前,先進行 Spring 的提前編譯(Ahead-of-Time, AOT)優化。
Step2 : 編譯:分為兩步:
Step3 : 打包:通過 Buildpack 打包,生成最小的應用可執行檔。
容器結構:容器內只有兩層:
AOT方式透過提前將應用程式編譯成原生機器碼,無需 JVM 即可運行,大幅減少了啟動時間和記憶體佔用,並生成更小、更高效的容器映像。
其他AOT編譯技術應用例子
- C/C++ 語言:
- 如 gcc 或 clang 等編譯器編譯C或C++程式時,所產生的就是直接為目標平台(例如:Linux、Windows)所編譯的機器碼。這就是AOT編譯的一個例子。
- .NET Core:
- NET Core提供了一個叫做crossgen的工具,可以將.NET的中間語言 (IL) 編譯成原生機器碼。這也是AOT的一種形式。
Truffle 是 GraalVM 的一個多語言實作框架,它允許不同的程式語言在同一個執行環境中無縫協作。這樣的設計讓 GraalVM 不僅僅侷限於運行 Java 程式,而是能夠同時支援多種語言,包括 JavaScript、Ruby、Python、R 和 WebAssembly 等。這種跨語言執行的能力對於需要多語言協作的應用場景具有很大的價值。
優勢特性如下
Truffle命名 : 很奇特的命名…像松露一樣小小的有價值